/*
 * memsetup-pxa.S :memory setup for PXA architectures
 *
 * Copyright (c) 2003, Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#ifdef HAVE_CONFIG_H
# include <blob/config.h>
#endif

#include <blob/arch.h>

.text

.globl memsetup
memsetup: 

	mov 	r10, lr

  	//Must set the GPIOs up before any chip selects will work

	//PSSR = 0x10 clear the PH bit in the PSSR
	ldr		r0,	=PSSR
	ldr		r1,	=0x10
	str		r1, [r0]

        nop
        nop
        nop
        nop
        nop

	// GPSR - put a 1 on any of the GPIOs (0=unchanged, 1=drive 1)
	ldr		r0,	=GPSR0
        ldr		r1,	=GPSR0_VAL
	str		r1, [r0]

	
	ldr		r0,	=GPSR1
        ldr		r1,	=GPSR1_VAL
	str		r1, [r0]

	ldr		r0,	=GPSR2
	ldr		r1,	=GPSR2_VAL
	str		r1, [r0]


	//GPCR - put a 0 on any of the GPIOs (0=unchanged, 1=drive 0)
	ldr		r0,	=GPCR0
	ldr		r1,	=GPCR0_VAL
	str		r1, [r0]

	ldr		r0,	=GPCR1
	ldr		r1,	=GPCR1_VAL
	str		r1, [r0]

	ldr		r0,	=GPCR2
	ldr		r1,	=GPCR2_VAL
	str		r1, [r0]


	//GPDR - put the GPIOs in the correct direction (0=in, 1=out)
	ldr		r0,	=GPDR0
        ldr		r1,	=GPDR0_VAL
	str		r1, [r0]

	ldr		r0,	=GPDR1
        ldr		r1,	=GPDR1_VAL
	str		r1, [r0]

	ldr		r0,	=GPDR2
	ldr		r1,	=GPDR2_VAL
	str		r1, [r0]

	//GAFR - setup the alternate functions (00=normal, 01=alt fuct 1, etc)
	ldr		r0,	=GAFR0_L
	ldr		r1,	=GAFR0_L_VAL
	str		r1, [r0]

	ldr		r0,	=GAFR0_U
	ldr		r1,	=GAFR0_U_VAL
	str		r1, [r0]

	ldr		r0,	=GAFR1_L
	ldr		r1,	=GAFR1_L_VAL
	str		r1, [r0]

	ldr		r0,	=GAFR1_U
	ldr		r1,	=GAFR1_U_VAL
	str		r1, [r0]

	ldr		r0,	=GAFR2_L
	ldr		r1,	=GAFR2_L_VAL
	str		r1, [r0]

	ldr		r0,	=GAFR2_U
	ldr		r1,	=GAFR2_U_VAL
	str		r1, [r0]

	//PSSR = 0x20 clear the RDH bit in the PSSR
	ldr		r0,	=PSSR
	ldr		r1,	=0x20
	str		r1, [r0]

	@********************************************************************            
	@ Initlialize Memory Controller
	@  The sequence below is based on the recommended init steps detailed
	@    in the EAS, chapter 5.
	@

        @ pause for 200 uSecs- allow internal clocks to settle
	@ *Note: only need this if hard reset... doing it anyway for now
	@

	
	@ ---- Wait 200 usec
	ldr r3, =OSCR
	mov r2, #0
	str r2, [r3] 
	ldr r4, =0x300			@ really 0x2E1 is about 200usec, so 0x300 should be plenty
1:	
	ldr r2, [r3] 
	cmp r4, r2
	bgt 1b


        @ get memory controller base address
        ldr     r1,  =MEMC_BASE

@****************************************************************************
@  Step 1
@

        @ write msc0, read back to ensure data latches
        @
        ldr     r2,   =MSC0_VAL
        str     r2,   [r1, #MSC0_OFFSET]
        ldr     r2,   [r1, #MSC0_OFFSET]

        @ write msc1
        ldr     r2,  =MSC1_VAL
        str     r2,  [r1, #MSC1_OFFSET]
        ldr     r2,  [r1, #MSC1_OFFSET]

        @ write msc2
        ldr     r2,  =MSC2_VAL
        str     r2,  [r1, #MSC2_OFFSET]
        ldr     r2,  [r1, #MSC2_OFFSET]

        @ write mecr
        ldr     r2,  =MECR_VAL
        str     r2,  [r1, #MECR_OFFSET]

        @ write mcmem0
        ldr     r2,  =MCMEM0_VAL
        str     r2,  [r1, #MCMEM0_OFFSET]

        @ write mcmem1
        ldr     r2,  =MCMEM1_VAL
        str     r2,  [r1, #MCMEM1_OFFSET]

        @ write mcatt0
        ldr     r2,  =MCATT0_VAL
        str     r2,  [r1, #MCATT0_OFFSET]

        @ write mcatt1
        ldr     r2,  =MCATT1_VAL
        str     r2,  [r1, #MCATT1_OFFSET]

        @ write mcio0
        ldr     r2,  =MCIO0_VAL
        str     r2,  [r1, #MCIO0_OFFSET]

        @ write mcio1
        ldr     r2,  =MCIO1_VAL
        str     r2,  [r1, #MCIO1_OFFSET]

        @ fly-by-dma is defeatured on this part
        @ write flycnfg
        @ldr     r2,  =FLYCNFG_SETTINGS
        @str     r2,  [r1, #FLYCNFG_OFFSET]

	
        @-------------------------------------------------------
        @ 3rd bullet, Step 1
        @

        @ get the mdrefr settings
        ldr     r3,  =MDREFR_VAL

        @ extract DRI field (we need a valid DRI field)
        @
        ldr     r2,  =0xFFF
        
        @ valid DRI field in r3
        @
        and     r3,  r3,  r2                 
        
        @ get the reset state of MDREFR
        @
        @zkj modify start ------------------------------
	@ldr     r4,  @[r1, #MDREFR_OFFSET]
        ldr     r4,   =0x03ca4000
        @zkj modify end ------------------------------
        
        @ clear the DRI field
        @
        bic     r4,  r4,  r2
        
        @ insert the valid DRI field loaded above
        @
        orr     r4,  r4,  r3
        
        @ write back mdrefr
        @
        str     r4,  [r1, #MDREFR_OFFSET]

        @zkj modify start ------------------------------
        ldr     r4,  [r1, #MDREFR_OFFSET]
        @zkj modify end ------------------------------

        @ *Note: preserve the mdrefr value in r4 *	

@****************************************************************************
@  Step 2
@

        @ fetch sxcnfg value
        @
        @ldr     r2,  =0
        @ write back sxcnfg
        @str     r2,  [r1, #SXCNFG_OFFSET]

        @ if sxcnfg=0, don't program for synch-static memory
        @cmp     r2,  #0
        @beq     1f

        @program sxmrs
        @ldr     r2,  =SXMRS_SETTINGS
        @str     r2,  [r1, #SXMRS_OFFSET]


@****************************************************************************
@  Step 3
@
        @zkj add start ------------------------------
	@set MDREFR according to user define with exception of a few bits
        ldr     r4, =MDREFR_VAL
	orr	r4, r4, #(MDREFR_SLFRSH)
	bic	r4, r4, #(MDREFR_E1PIN|MDREFR_E0PIN)
	str	r4, [r1, #MDREFR_OFFSET]
	ldr	r4, [r1, #MDREFR_OFFSET]

    	@Step 3b: de-assert MDREFR:SLFRSH
	bic	r4, r4, #(MDREFR_SLFRSH)
	str	r4, [r1, #MDREFR_OFFSET]
	ldr	r4, [r1, #MDREFR_OFFSET]

	@Step 3c: assert MDREFR:E1PIN and E0PIO as desired
	ldr	r4, =MDREFR_VAL
	str	r4, [r1, #MDREFR_OFFSET]
	ldr	r4, [r1, #MDREFR_OFFSET]
        @zkj add end ------------------------------

@****************************************************************************
@  Step 4
@

        @ fetch platform value of mdcnfg
        @
        ldr     r2,  =MDCNFG_VAL                       

        @ disable all sdram banks
        @
        bic     r2,  r2,  #(MDCNFG_DE0 | MDCNFG_DE1)
        bic     r2,  r2,  #(MDCNFG_DE2 | MDCNFG_DE3)

        @ program banks 0/1 for bus width
        @
        bic   r2,  r2,  #MDCNFG_DWID0      @0=32-bit


        @ write initial value of mdcnfg, w/o enabling sdram banks
        @
        str     r2,  [r1, #MDCNFG_OFFSET]

@ ****************************************************************************
@  Step 5
@
        
        @ pause for 200 uSecs
        @
    	ldr r3, =OSCR_BASE              @reset the OS Timer Count to zero
    	mov r2, #0 
	str r2, [r3] 
	ldr r4, =0x300			@really 0x2E1 is about 200usec, so 0x300 should be plenty
1:	
	ldr r2, [r3] 
	cmp r4, r2
	bgt 1b
        

@****************************************************************************
@  Step 6
@

	mov    r0, #0x78				    @turn everything off 
      	mcr    p15, 0, r0, c1, c0, 0		@(caches off, MMU off, etc.)

@ ****************************************************************************
@  Step 7
@
        @ Access memory *not yet enabled* for CBR refresh cycles (8)
        @ - CBR is generated for all banks
        
	ldr     r2, =SDRAM_BASE
	str     r2, [r2]
	str     r2, [r2]
	str     r2, [r2]
	str     r2, [r2]
	str     r2, [r2]
	str     r2, [r2]
	str     r2, [r2]
	str     r2, [r2]


@ ****************************************************************************
@  Step 8: NOP (enable dcache if you wanna... we dont)
@


@ ****************************************************************************
@  Step 9
@


        @get memory controller base address
        @
        ldr     r1,  =MEMC_BASE

        @fetch current mdcnfg value
        @
        ldr     r3,  [r1, #MDCNFG_OFFSET]

        @enable sdram bank 0 if installed (must do for any populated bank)
        @
        orr     r3,  r3,  #MDCNFG_DE0

        @write back mdcnfg, enabling the sdram bank(s)
        @
        str     r3,  [r1, #MDCNFG_OFFSET]


@****************************************************************************
@  Step 10
@
        
        @ write mdmrs
        @
        ldr     r2,  =MDMRS_VAL
        str     r2,  [r1, #MDMRS_OFFSET]
        
        

@INITINTC        
        @********************************************************************
        @ Disable (mask) all interrupts at the interrupt controller
        @

        @ clear the interrupt level register (use IRQ, not FIQ)
        @
        mov     r1, #0
        ldr     r2,  =ICLR
        str     r1,  [r2]
        
        @ mask all interrupts at the controller
        @       
        ldr     r2,  =ICMR

        str     r1,  [r2]


	@ Turn Off ALL on-chip peripheral clocks for re-configuration
	@
        ldr     r1,  =CKEN
        mov     r2,  #0
        str     r2,  [r1]

        @
        @ With this info, let's set up the CCCR {T/R/M/SD} accordingly
        @ *SDCLK = MEMClk/2 forced eariler
        @
        @ default value in case no valid rotary switch setting is found
        ldr     r2, =(CCCR_L27 | CCCR_M2 | CCCR_N10)        @ DEFAULT: {200/200/100}


        @... and write the core clock config register
        @
        ldr     r1,  =CCCR
        str     r2,  [r1]

        @ enable the 32Khz oscillator for RTC and PowerManager
        @
        ldr     r1,  =OSCC
        mov     r2,  #OSCC_OON  
        str     r2,  [r1]

	
        @ NOTE:  spin here until OSCC.OOK get set,
        @        meaning the PLL has settled.
        @ 
60:        
        ldr     r2, [r1]
        ands    r2, r2, #1
        beq     60b

	/* Mask all interrupts */
	ldr	r0, =ICMR
	mov	r1, #0
	str	r1, [r0]

	//Disable software and data breakpoints
	mov	r0, #0
	mcr	p15,0,r0,c14,c8,0  // ibcr0
	mcr	p15,0,r0,c14,c9,0  // ibcr1
	mcr	p15,0,r0,c14,c4,0  // dbcon

	//Enable all debug functionality
	mov	r0,#0x80000000
	mcr	p14,0,r0,c10,c0,0  // dcsr


endmemsetup:

    mov     pc, lr
